﻿//'    This file is part of The Global Distribution System.

//'    The Global Distribution System is free software: you can redistribute it and/or modify
//'    it under the terms of the GNU General Public License as published by
//'    the Free Software Foundation, either version 3 of the License, or
//'    (at your option) any later version.

//'    The Global Distribution System is distributed in the hope that it will be useful,
//'    but WITHOUT ANY WARRANTY; without even the implied warranty of
//'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//'    GNU General Public License for more details.

//'    You should have received a copy of the GNU General Public License
//'    along with The Global Distribution System.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Windows.Forms;
using GlobalDistributionServer;
using HyperGTS.Properties;
using System.IO;

namespace HyperGTS
{
    public partial class FormHyperGts : Form
    {
                
        public FormHyperGts()
        {
            try
            {
                InitializeComponent();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                //throw;
            }
            
        }

        #region Variables

        private static GDS _gds = new GDS();
        private static DNS_Main _dns = new DNS_Main();
        private readonly GTS _gts = new GTS(ref _gds, ref _dns);

        #endregion

        #region Delegates
        
        private delegate void DGts(string log);

        private void GtsLog(string log)
        {
            if (LB_GTS_Log.InvokeRequired)
            {
                LB_GTS_Log.Invoke(new DGts(GtsLog), log);
            }
            else
            {
                LB_GTS_Log.Items.Add(DateTime.Now.ToLongTimeString() + ": " + log);
                LB_GTS_Log.SelectedIndex = LB_GTS_Log.Items.Count - 1;
            }
        }

        private delegate void DGds(string log);

        private void GdsLog(string log)
        {
            if (LB_GDS_Log.InvokeRequired)
            {
                LB_GDS_Log.Invoke(new DGds(GdsLog), log);
            }
            else
            {
                LB_GDS_Log.Items.Add(DateTime.Now.ToLongTimeString() + ": " + log);
                LB_GDS_Log.SelectedIndex = LB_GDS_Log.Items.Count - 1;
            }
        }
        
        private delegate void DDns(string log);

        private void DnsLog(string log)
        {

            if (LB_DNS_Log.InvokeRequired)
            {
                LB_DNS_Log.Invoke(new DDns(DnsLog), log);
            }
            else
            {
                LB_DNS_Log.Items.Add(DateTime.Now.ToLongTimeString() + ": " + log);
                LB_DNS_Log.SelectedIndex = LB_DNS_Log.Items.Count - 1;
            }

        }

        private delegate void DGtsCount(int count);

        private void GtsCount(int count)
        {
            if (LB_POKEMON.InvokeRequired)
            {
                LB_POKEMON.Invoke(new DGtsCount(GtsCount), count);
            }
            else
            {
                LB_POKEMON.Text = string.Format("Pokémon sent: {0}", count);
            }
        }

        #endregion

        #region Subs stuff

        private void Form1Load(object sender, EventArgs e)
        {
            // Setup Handlers.
            if (_gds != null) _gds.GeneralLog += GdsLog;
            if (_dns != null) _dns.Logger += DnsLog;
            if (_gts != null)
            {
                _gts.LogEvent += GtsLog;
                _gts.PokemonCount += GtsCount;
            }
            // Setup Information.
            TB_IPADDRESS.Text = _dns.GetExternalIP();
            CBOX_MODE.SelectedIndex = 0;
            var info = "Version Information";
            info += Environment.NewLine;
            if (_gts != null) info += string.Format("GTS: v{0}{1}", _gts.Version, Environment.NewLine);
            if (_gds != null) info += string.Format("GDS: v{0}{1}", _gds.Version, Environment.NewLine);
            if (_dns != null) info += string.Format("DNS: v{0}{1}", _dns.Version, Environment.NewLine);
            info += string.Format("Build Date: {0}{1}", Environment.NewLine, RetrieveLinkerTimestamp(Application.ExecutablePath).ToUniversalTime());
            LBL_VERSION.Text = info;
        }

        private void Button1Click(object sender, EventArgs e)
        {
            // Switch
            switch (BT_GTS.Text.ToLower())
            {
                // Start the GTS.
                case "start gts":
                    if(CBOX_MODE.SelectedIndex == 0)
                    {
                        // Distribution Mode, determine which one.
                        if(RB_GTS_SendOne.Checked)
                        {
                            GtsLog("Individual Distribution Mode Activated.");
                            _gts.DistributionMode = GTS.ModeType.Invididual;
                            _gts.PokemonFile = TB_GTS_SendPKMN.Text;
                        }

                        if(RB_GTS_SendFolder.Checked)
                        {
                            if(CB_RANDOMIZE.Checked)
                            {
                                GtsLog("Randomized Distribution Mode Activated.");
                                _gts.DistributionMode = GTS.ModeType.RandomFolder;
                            }
                            else
                            {
                                GtsLog("Alphabetical Distribution Mode Activated.");
                                _gts.DistributionMode = GTS.ModeType.Folder;    
                            }
                            _gts.PokemonFolder = TB_GTS_SendPKMN.Text;
                        }
                    
                    }
                    else
                        // Receive Mode.
                    {
                        GtsLog("Receive Mode Activated.");
                        _gts.DistributionMode = GTS.ModeType.Receive;
                    }

                    BT_GTS.Text = Resources.FormHyperGts_Button1Click_STOP_GTS;
                    GtsLog(string.Empty);
                    _gts.Start();
                    break;

                // Stop the GTS
                case "stop gts":
                    _gts.Stop();
                    GtsLog("GTS Stopped");
                    BT_GTS.Text = Resources.FormHyperGts_Button1Click_START_GTS;
                    break;
            }
        }

        private void CboxModeSelectedIndexChanged(object sender, EventArgs e)
        {
            // Index changed.
            switch (CBOX_MODE.SelectedIndex)
            {
                // Case 0: Uploading Enabled.
                case 0:
                    GB_DM.Enabled = true;
                    break;
                // Case 1: Uploading Disabled.
                case 1:
                    GB_DM.Enabled = false;
                    break;
            }
        }

        private void BtGetipClick(object sender, EventArgs e)
        {
            TB_IPADDRESS.Text = _dns.GetExternalIP();
        }

        private void BtStartDnsClick(object sender, EventArgs e)
        {

            if (TB_IPADDRESS.Text != string.Empty && _dns.IsIPv4(TB_IPADDRESS.Text))
            {

                _dns.fakeIP = TB_IPADDRESS.Text;
                _dns.Start();
                BT_STARTDNS.Enabled = false;
                BT_GETIP.Enabled = false;
                TB_IPADDRESS.ReadOnly = true;
                BT_STOPDNS.Enabled = true;

            }
            else
            {
                DnsLog("Fill in a valid IP address in the textbox!");
            }
        }

        private void BtStopdnsClick(object sender, EventArgs e)
        {
            _dns.Stop();
            DnsLog("DNS Stopped");
            BT_STARTDNS.Enabled = true;
            BT_GETIP.Enabled = true;
            TB_IPADDRESS.ReadOnly = false;
            BT_STOPDNS.Enabled = false;
        }

        private void LlDnsClearLogLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            LB_DNS_Log.Items.Clear();
        }

        private void LDnsClearLogLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            LB_GDS_Log.Items.Clear();
        }

        private void FormHyperGtsFormClosing(object sender, FormClosingEventArgs e)
        {
            // Undo Handlers.
            _gds.GeneralLog -= GdsLog;
            _dns.Logger -= DnsLog;
            _gts.LogEvent -= GtsLog;
            _gts.PokemonCount -= GtsCount;

            // Stop.
            _dns.Stop();
            _gds.Stop();
            _gts.Stop();

            // Dispose.
            _gds.Dispose();
        }

        private void LbGdsLogDoubleClick(object sender, EventArgs e)
        {
            MessageBox.Show(LB_GDS_Log.SelectedItem.ToString(), Resources.FormHyperGts_LbGdsLogDoubleClick_Expanded_Log);
        }

        private void LbGtsLogDoubleClick(object sender, EventArgs e)
        {
            MessageBox.Show(LB_GTS_Log.SelectedItem.ToString(), Resources.FormHyperGts_LbGdsLogDoubleClick_Expanded_Log);
        }

        private void BtGdsusrmgrClick(object sender, EventArgs e)
        {
            _gds.ShowClientManager();
        }

        private void BtGdsoptionsClick(object sender, EventArgs e)
        {
            _gds.ShowOptions();
        }

        private static DateTime RetrieveLinkerTimestamp(string filePath)
        {
            const int peHeaderOffset = 60;
            const int linkerTimestampOffset = 8;

            var b = new byte[2048];
            var s = default(Stream);
            try
            {
                s = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                s.Read(b, 0, 2048);
            }
            finally
            {
                if ((s != null))
                    s.Close();
            }

            var i = BitConverter.ToInt32(b, peHeaderOffset);

            var secondsSince1970 = BitConverter.ToInt32(b, i + linkerTimestampOffset);
            var dt = new DateTime(1970, 1, 1, 0, 0, 0);
            dt = dt.AddSeconds(secondsSince1970);
            dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours);
            return dt;
        }
        
        #endregion



    }
}